﻿/**
@author 迷途小羔羊
2012.1.22
*/
module GYLite
{
																		
														
	/**羔羊组件的基类容器，使用羔羊组件时，建议至少使用此容器或者此容器的继承容器
	 * 羔羊组件并不屏蔽原生的sprite、shape(可以使用s.addChild s.addChildAt等)，但是原生的容器类不参与组件布局或者计算
	 * 所以建议使用GYSprite代替Sprite*/
	export class GYSprite extends egret.Sprite implements IGYInteractiveDisplay,IGYContainer,IUpdate,IBatch
	{		
		protected static _mouseDownVec:MouseRelease[];
		protected static _mouseWheelVec:MouseWheel[];
		public static $skinTheme:ISkinTheme;
		/**内部使用*/public static mouseDownEvent:egret.TouchEvent;
		public static _matrix:egret.Matrix;
		public static _rect:egret.Rectangle;
		public static _pt:egret.Point;
		/**请在初始化之后下一帧读取此值,此前为null*/public static player:any;
		public static _globalDragList:GYGroup[];
		public static stageX:number;
		public static stageY:number;
		private static _touchDict:any;
		public static isMobile:boolean;
		public static hashCode:number = 10000000;
		public static globalVDrag:number = 0;
		public static globalVDragCount:number = 3;
		public static globalHDrag:number = 0;
		public static globalHDragCount:number = 3;
		protected static _root:egret.DisplayObjectContainer;
		/**暂时没用*/public static useStarling:boolean;
		/**版本号*/public static version:string="v2.0.4";
		
		
		public static $stage:egret.Stage;
		public static $disposed:boolean;
		private static playerInited(stg:egret.Stage):void
		{
			if(window['player'])
				GYSprite.player = window['player'];
			else
			{
				var list:any = document.querySelectorAll(".egret-player");
				var len:number = list.length;
				while(--len>-1)
				{
					if(list[len]["egret-player"] == null)
						continue;
					if(list[len]["egret-player"].stage.hashCode == stg.hashCode)
					{
						GYSprite.player = list[len]["egret-player"];						
						//alert(GYSprite.player.canvas.getBoundingClientRect());
					}
						
				}
			}
			if(GYSprite.player == null)
				setTimeout(GYSprite.playerInited, 0,stg);
		}
		/**初始化组件库，在组件库使用之前必须先调用此方法初始化
		 * @param stg 舞台
		 * @param theme 主题
		 * @param rt 根容器容器，默认为null，使用stg作为根容器		 
		*/
		public static Init(stg:egret.Stage, theme:ISkinTheme, rt:egret.DisplayObjectContainer=null):void
		{
			if(GYSprite.$stage)return;
			GYSprite._root = rt;
			GYSprite._touchDict = {};
			if(GYSprite._root)
				GYSprite._root.addEventListener(egret.Event.REMOVED_FROM_STAGE, GYSprite.dispose,GYSprite._root);
			else
				GYSprite._root = stg;			
			setTimeout(GYSprite.playerInited, 0,stg);
			enable(stg);			
			GYLoader.wxreq = egret.wxgame.wx?egret.wxgame.wx.request:null;
			GYSprite.isMobile = egret.Capabilities.isMobile;
			GYSprite.$stage=stg;			
			GYSprite.$stage.addEventListener(egret.TouchEvent.TOUCH_END, GYSprite.stageMouseUp, GYSprite.$stage);
			// document.addEventListener("mousemove",GYSprite.stageMouseMove);
			document.addEventListener("mouseup", GYSprite.stageMouseUp);
			document.addEventListener("mousewheel", GYSprite.stageMouseWheel);
			GYSprite._mouseDownVec = new Array<MouseRelease>();
			GYSprite._mouseWheelVec = new Array<MouseWheel>();
			GYSprite.mouseDownEvent = new egret.TouchEvent(egret.TouchEvent.TOUCH_BEGIN);
			GYSprite._globalDragList= new Array<GYGroup>();
			GYSprite._matrix=new egret.Matrix;
			GYSprite._rect = new egret.Rectangle;
			GYSprite._pt = new egret.Point;			
			CommonUtil.Init(stg);
			TimeManager.init();
			LayoutManager.Init(stg);
			DragManager.Init();
			GYImage.init();
			GYTextBase.init();
			// GYDrawBitmapData.setResCheck(120000);			
			if(theme)GYSprite.skinTheme = theme;
			// var tf:GYText = new GYText;
			// var temp:number;
			// var str:string = "宋体空格模拟首行缩进";
			// tf.htmlText = "<font size='2' fontfamily='宋体'> </font>" + str;			
			// temp = tf.width;
			// tf.htmlText = "<font size='2' fontfamily='宋体'>  </font>" + str;
			// GYText.indentSize = tf.width - temp;			
		}
		public static get disposed():boolean
		{
			return GYSprite.$disposed;
		}
		public static dispose(e:egret.Event=null):void
		{
			if(GYSprite.$disposed)return;			
			GYSprite.$disposed = true;
			GYSprite._root.removeEventListener(egret.Event.REMOVED_FROM_STAGE, GYSprite.dispose,GYSprite._root);
			GYSprite.$stage.removeEventListener(egret.TouchEvent.TOUCH_END, GYSprite.stageMouseUp,GYSprite.$stage);
			GYSprite.$stage.removeEventListener(egret.TouchEvent.TOUCH_BEGIN, GYSprite.stageMouseDown,GYSprite.$stage);
			document.removeEventListener("mouseup", GYSprite.stageMouseUp);
			document.removeEventListener("mousewheel", GYSprite.stageMouseWheel);			
		}
		/**对引擎进行垃圾回收*/
		public static gc():void
		{
			DraggerHandle.gc();
			GYTween.gc();
			CommonUtil.gc();
		}
		// public static stageMouseMove(e)
		// {
		// 	if(!GYSprite.player)return;
		// 	GYSprite.stageX = (e.clientX - GYSprite.player.canvas.offsetLeft)/egret.sys.DisplayList.$canvasScaleX;///egret.sys.DisplayList.$canvasScaleX;
		// 	GYSprite.stageY = (e.clientY - GYSprite.player.canvas.offsetTop)/egret.sys.DisplayList.$canvasScaleY;//*egret.sys.DisplayList.$canvasScaleY;			
		// 	//console.log(e.localX,e.localY);
		// }
		/**Stage舞台*/
		public static get stage():egret.Stage
		{
			return GYSprite.$stage;
		}
		/** 全局的鼠标按下回调,请使用GYSprite.addStageDown添加回调侦听 */
		private static stageMouseDown(e:egret.TouchEvent):void
		{
			
		}
		public static removeTouch(touchPointID:number):void
		{			
			touchPointID = Number(touchPointID);
			if(touchPointID != touchPointID)return;
			delete GYSprite._touchDict[touchPointID];
		}
		public static addTouch(touchPointID:number,x:number,y:number):void
		{
			let obj:any;
			touchPointID = Number(touchPointID);
			if(touchPointID != touchPointID)return;
			if(GYSprite._touchDict[touchPointID] == null)
				GYSprite._touchDict[touchPointID] = {};
			obj = GYSprite._touchDict[touchPointID];
			obj.touchX = x;
			obj.touchY = y;
			obj.touchPointID = touchPointID;
		}
		public static getTouch(touchPointID:number):any
		{
			return GYSprite._touchDict[touchPointID];
		}
		public static getTouchX(touchPointID:number=0):number
		{
			return GYSprite._touchDict[touchPointID]?GYSprite._touchDict[touchPointID].touchX:NaN;
		}
		public static getTouchY(touchPointID:number=0):number
		{
			return GYSprite._touchDict[touchPointID]?GYSprite._touchDict[touchPointID].touchY:NaN;
		}		
		/** 全局的鼠标滚轮,请使用GYSprite.addStageWheel添加回调侦听 */
		protected static stageMouseWheel(e):void
		{
			var len:number;
			len = GYSprite._mouseWheelVec.length;
			while(--len>-1)
			{
				let mouseWheel:MouseWheel = GYSprite._mouseWheelVec[len];
				if(mouseWheel.display["isRollOver"])
					mouseWheel.callBack.call(mouseWheel.thisObject,e);
			}
		}
		/**添加舞台滚轮对象
		 * @param sp 显示对象
		 * @param mouseWheelFunc(e:GYTouchEvent):void 鼠标滚动时的回调函数		 
		 * */
		public static addStageWheel(sp:IGYDisplay, mouseWheelFunc:Function=null, thisObject:any = null):void
		{
			if(sp == null)return;
			if(GYSprite.findMouseWheel(sp,mouseWheelFunc) != null)return;
			var r:MouseWheel = MouseWheel.getInstance(sp,mouseWheelFunc,thisObject);
			GYSprite._mouseWheelVec.push(r);
		}
		/**移除舞台滚轮对象
		 * @param sp 显示对象
		 * @param mouseWheelFunc(e:GYTouchEvent):void 鼠标滚动时的回调函数		 		 
		 * */
		public static removeStageWheel(d:IGYDisplay, func:Function=null):void
		{
			var len:number;
			len = GYSprite._mouseWheelVec.length;
			while(--len>-1)
			{
				if(GYSprite._mouseWheelVec[len].display == d && (func == null || GYSprite._mouseWheelVec[len].callBack == func))
					GYSprite._mouseWheelVec.splice(len,1);
			}
		}
		protected static findMouseWheel(d:IGYDisplay, func:Function=null):MouseWheel
		{
			var len:number;
			len = GYSprite._mouseWheelVec.length;
			while(--len>-1)
			{
				if(GYSprite._mouseWheelVec[len].display == d && (func == null || GYSprite._mouseWheelVec[len].callBack == func))
					return GYSprite._mouseWheelVec[len];
			}
			return null;
		}
		/** 全局的鼠标抬起回调,请使用GYSprite.addStageDown添加回调侦听 */
		protected static stageMouseUp(e):void
		{
			if(e.target.nodeName == "CANVAS")
				return;
			if (GYSprite._mouseDownVec.length > 0)
			{
				var len:number;
				var mDownSp:IGYDisplay,t:egret.DisplayObject;				
				var isClear:boolean;
				var r:MouseRelease;
				len = GYSprite._mouseDownVec.length;
				while(--len>-1)
				{
					r = GYSprite._mouseDownVec[len];
					if(r.touchPointID == r.touchPointID && r.touchPointID != e.touchPointID)continue;
					mDownSp = r.display;
					if(!mDownSp.hasEventListener(GYTouchEvent.RELEASE_OUTSIDE) || mDownSp.disposed)
					{
						r.clear();
						GYSprite._mouseDownVec.splice(len,1);
						continue;
					}
					t = e.target;					
					while(t != GYSprite.$stage && <any>t != mDownSp)
					{
						if(t == null)
						{
							isClear = true;
							break;
						}
						t = t.parent;
					}
					if(t == GYSprite.$stage || t == null)
					{
						var gyEvent:GYTouchEvent = new GYTouchEvent(GYTouchEvent.RELEASE_OUTSIDE,false,false,e.stageX,e.stageY,e.touchPointID);						
						gyEvent.outsideTarget = e.target;						
						mDownSp.dispatchEvent(gyEvent);
						if(gyEvent.result == 0)
							isClear = true;
					}
					if(isClear || !r.untilUp)
					{
						r.clear();
						GYSprite._mouseDownVec.splice(len,1);
					}
				}
			}
		}
		/**添加舞台点击对象
		 * @param sp 显示对象
		 * @param mouseUpFunc(e:GYTouchEvent):void 鼠标抬起时的回调函数
		 * @param uUp 是否监听直到鼠标在外部释放 GYTouchEvent的result为1时，则会一直监听，默认false
		 * @param touchPointID 触摸id，默认为NaN，即任意id的手指抬起均触发
		 * */
		public static addStageDown(sp:IGYDisplay, mouseUpFunc:Function=null, thisObject:any = null, uUp:boolean=false,touchPointID:number=NaN):void
		{
			if(sp == null)return;
			if(GYSprite.findMouseRel(sp,mouseUpFunc) != null)return;
			var r:MouseRelease = MouseRelease.getInstance(sp,mouseUpFunc,thisObject,touchPointID);						
			r.untilUp = uUp;
			GYSprite._mouseDownVec.push(r);
		}
		/**是否当前鼠标按下的对象
		 * @param sp 显示对象
		 * @return Boolean
		 * */
		public static isStageDown(sp:IGYDisplay):boolean
		{
			if(GYSprite.findMouseRel(sp) == null)
				return false;
			return true;
		}
		
		protected static findMouseRel(d:IGYDisplay, func:Function=null):MouseRelease
		{
			var len:number;
			len = GYSprite._mouseDownVec.length;
			while(--len>-1)
			{
				if(GYSprite._mouseDownVec[len].display == d && (func == null || GYSprite._mouseDownVec[len].callBack == func))
					return GYSprite._mouseDownVec[len];
			}
			return null;
		}
		protected static hasGlobalVDrag():boolean
		{
			var len:number;
			var sp:GYGroup;
			len = GYSprite._globalDragList.length;
			while(--len>-1)
			{
				if(GYSprite._globalDragList[len].verticalDrag)
					return true;
			}
			return false;
		}
		protected static hasGlobalHDrag():boolean
		{
			var len:number;
			len = GYSprite._globalDragList.length;
			while(--len>-1)
			{
				if(GYSprite._globalDragList[len].horizonDrag)
					return true;
			}
			return false;
		}
		protected static pushGlobalDrag(sp:GYGroup):boolean
		{
			if(GYSprite._globalDragList.indexOf(sp) == -1)
				GYSprite._globalDragList.push(sp);
			return GYSprite._globalDragList.length == 1;
		}
		/**1纵向 2横向*/
		protected static shiftGlobalDrag(policy:number):boolean
		{
			var sp:GYGroup;
			GYSprite._globalDragList.shift();
			if(GYSprite._globalDragList.length > 0)
			{
				sp = GYSprite._globalDragList[0];
				while(sp)
				{
					if(policy == 1 && sp.verticalDrag || policy == 2 && sp.horizonDrag)
					{
						sp.dispatchEvent(new GYEvent(GYEvent.GLOABL_DRAG));
						return true;						
					}
					GYSprite._globalDragList.shift();
					sp.clearGlobalDrag();
					sp = GYSprite._globalDragList[0];
				}
			}
			return false;
		}
		protected static clearGlobalDrags():void
		{
			var len:number;
			len = GYSprite._globalDragList.length;
			while(--len>-1)
			{
				GYSprite._globalDragList[len].clearGlobalDrag();
			}
			GYSprite._globalDragList.length = 0;
			GYSprite.globalHDrag = GYSprite.globalVDrag = 0;
		}
		/**
		 * 设置主题皮肤，监听GYThemeEvent.THEME_CHANGE通知
		 * */
		public static set skinTheme(val:ISkinTheme)
		{
			GYSprite.$skinTheme = val;
			GYSprite.$skinTheme.initRes();
			GYSprite.$stage.dispatchEvent(new GYThemeEvent(GYThemeEvent.THEME_CHANGE));
		}
		
		public static get skinTheme():ISkinTheme
		{
			return GYSprite.$skinTheme;
		}
		
		public $width:number;
		public $height:number;
		public $layoutParent:GYUIComponent;
		protected _layoutMode:LayoutMode;
		protected _invalidDisplay:boolean;
		protected _invalidLayout:boolean;
		protected _updating:boolean;
		protected _toolTip:GYToolTip;
		protected _toolTipOffsetX:number;
		protected _toolTipOffsetY:number;
		protected _toolTipString:string;
		protected _toolTipKeep:boolean;
		protected _followTarget:GYSprite;
		protected _toolTipOnKeep:boolean;
		private _doubleClkTime:number;
		private _doubelClk:number;
		/**GYSprite元素列表*/
		protected elementVec:IGYDisplay[];
		protected _bound:egret.Rectangle;
		protected _elementbound:egret.Rectangle;
		protected _invalidZIndex:boolean;
		protected _disabledZIndex:boolean;
		public $disposed:boolean;		
		/**防销毁锁定标志，为true则不会被dispose销毁，除非参数forceDispose为true*/public disposeLock:boolean;
		/**是否tip跟随鼠标*/public isTipFollow:boolean;
		/**是否不参与布局计算*/public offLayout:boolean;
		/**视图坐标变化通知很多时候不需通知父级，可用此控制是否使用*/
        public posCallUpdate=false;
        /**视图变化通知很多时候不需通知父级，可用此控制是否使用*/
        public viewChangeCallParent=false;
		/**鼠标经过时手型，true为默认手指或者指定一个网络图片，32X32以下*/public buttonModeForMouse:any;
		protected _invalidBatch:boolean;		
		protected _batchDrawParam:BatchDrawParam;		
		protected _batch:boolean;
		protected _batchAtlasName:string;		
		public constructor()
		{
			super();
			var s = this;			
			s._batchDrawParam = null;
			s.mouseThrough = false;
			s.rectHit = false;
			s.offLayout= false;
			s.$disposed = false;
			s.disposeLock = false;
			s.$width=NaN;
			s.$height=NaN;
			s.$layoutParent=null;
			s._layoutMode=null;
			s._invalidDisplay=false;
			s._invalidLayout=false;
			s._updating=false;
			s._toolTip=null;
			s._toolTipOffsetX=0;
			s._toolTipOffsetY=0;
			s._toolTipString=null;
			s._toolTipKeep=false;
			s._followTarget=null;
			s._toolTipOnKeep=false;			
			s._doubleClkTime=0;
			s._doubelClk = 0;
			s._invalidZIndex = false;
			s._disabledZIndex = true;
			s.elementVec=new Array<IGYDisplay>();
			s._layoutMode = new LayoutMode;
			s._bound = new egret.Rectangle;
			s._elementbound = new egret.Rectangle;	
			// s.$graphics.$setTarget(null);
			s.$graphics = new GYLite.GYGraphics(s);
		}
		public clearBatch():void
		{
		}
		public setBatchDrawParam(val:BatchDrawParam):void
		{
			this._batchDrawParam = val;
		}
		/**合批图像的绘制样式**/
		public getBatchDrawParam():BatchDrawParam
		{
			return this._batchDrawParam;
		}
		public setBatchAtlasName(val:string)
		{
			let s= this;
			s._batchAtlasName = val;			
		}
		/**合批图集名称，不存在找父级容器的，如果都不存在，默认AtlasRender.defaultAtlasName**/
		public getBatchAtlasName():string
		{
			let s = this;
			if(s._batchAtlasName!=null)
				return s._batchAtlasName;
			let pr:GYSprite;
			pr = <GYSprite>s.$parent;	
			return pr && pr.getBatchAtlasName?pr.getBatchAtlasName():AtlasRender.defaultAtlasName;;
		}
		/** 舞台渲染前执行 */
		protected displayChg():void
		{
			var s = this;
			LayoutManager.addRenderFunc(this);
		}
		
		public get mouseX():number
		{
			var s = this;
			s.globalToLocal(GYSprite.stageX, GYSprite.stageY, GYSprite._pt);
			return GYSprite._pt.x;
		}
		public get mouseY():number
		{
			var s = this;
			s.globalToLocal(GYSprite.stageX, GYSprite.stageY, GYSprite._pt);
			return GYSprite._pt.y;
		}		
		public get touch():number
		{
			var s = this;
			s.globalToLocal(GYSprite.stageX, GYSprite.stageY, GYSprite._pt);
			return GYSprite._pt.y;
		}
		/**设置双击回调*/
		public setDoubleClk(func:Function, thisObject):void
		{
			var s = this;
			s.addEventListener(egret.TouchEvent.TOUCH_TAP, function(e:egret.TouchEvent):void{			
			if(CommonUtil.loopTime - s._doubleClkTime > 500)
			{
				s._doubleClkTime = CommonUtil.loopTime;
				s._doubelClk = 1;
				return;
			}				
			// s._doubleClkTime = CommonUtil.loopTime;
			++s._doubelClk;
			if(s._doubelClk > 1)
			{
				s._doubleClkTime = 0;
				s._doubelClk = 0;
				e.$type = "doubleClick";
				func.call(thisObject,e);
			}
			},s);
		}
		/**设置滚轮回调 */
		private _wheelFunc:Function;
		public setWheelFunc(func:Function, thisObject:any=null):void
		{
			var s = this;
			// var f = function(e){func.call(thisObject,e)};
			// var rollOutFunc = function(e:MouseEvent){
			// 		document.removeEventListener("mousewheel", f);	
			// 		s.removeEventListener(MouseEvent.ROLL_OUT, rollOutFunc,s);
			// 		delete s["isRollOver"];						
			// 	};
			// var rollOverFunc = function(e:MouseEvent):void{
			// 	document.addEventListener("mousewheel", f);
			// 	s.addEventListener(MouseEvent.ROLL_OUT, rollOutFunc,s);
			// };
			// if(s._wheelFunc!=null)
			// 	s.removeEventListener(MouseEvent.ROLL_OVER, rollOverFunc,s);
			// s._wheelFunc = func;
			// if(s._wheelFunc!=null)
			// 	s.addEventListener(MouseEvent.ROLL_OVER, rollOverFunc,s);
			if(func == null)
				GYSprite.removeStageWheel(s,func);
			else
				GYSprite.addStageWheel(s,func,thisObject);
		}
		
		/**获取所有对象边界矩形*/
		public getAllBounds(t:IGYDisplay):egret.Rectangle
		{var s = this;
			if(s.scrollRect && !s.scrollRect.isEmpty())
				return s.scrollRect;
			let rect:egret.Rectangle = s.getBounds(s._bound);
			if(s.parent)
			{
				rect.x += s.x;
				rect.y += s.y;
			}
			return rect;
		}
		/**获取所有对象边界矩形**/
		public getElementsBounds(t:IGYDisplay):egret.Rectangle
		{var s = this;
			if(s.scrollRect && !s.scrollRect.isEmpty())
				return s.scrollRect;
			let rect:egret.Rectangle = s.getBounds(s._elementbound);			
			if(s.parent)
			{
				rect.x += s.x;
				rect.y += s.y;
			}
			return rect;
		}
		/**根据索引获取元素 */
		public getElementAt(index:number):IGYDisplay
		{var s = this;
			if(index >= s.elementVec.length)
			{
				throw(new Error("索引" + index + "超出范围！"));				
			}
			return s.elementVec[index];
		}
		/**根据获取元素层级 */
		public getElementIndex(child:IGYDisplay):number
		{var s = this;
			var len:number;
			len = s.elementVec.length;
			while(--len>-1)
			{
				if(s.elementVec[len] == child)
					return len;
			}
			return -1;
		}
		/**删除元素*/
		public delElement(child:IGYDisplay):void
		{var s = this;
			var delIndex:number=s.elementVec.indexOf(child);
			if(delIndex >= 0)
				s.elementVec.splice(delIndex,1);
		}
		
		/**添加元素 */
		public addElement(child:IGYDisplay):IGYDisplay
		{var s = this;
			if(s.elementVec.length > 0 && s.elementVec[s.elementVec.length-1] == child)
				return child;			
			if(child.parent)
				(child.parent as GYSprite).delElement(child);
			s.elementVec.push(child);
			s.addChild(<egret.DisplayObject><any>child);
			s.invalidZIndex();
			return child;
		}
		
		/**添加元素到指定层级*/
		public addElementAt(child:IGYDisplay, index:number):IGYDisplay
		{var s = this;
			if(index < s.elementVec.length && s.elementVec[index] == child)
				return child;
			if(index > -1)
			{
				// var delIndex:number=s.elementVec.indexOf(child);
				// if(delIndex == -1)
				// {
				// 	if(child.parent)
				// 		(child.parent as GYSprite).delElement(child);
				// }
				// if(delIndex != index)
				// {
				// 	if(delIndex >= 0)
				// 		s.elementVec.splice(delIndex,1);
				// 	s.elementVec.splice(index,0,child);
				// }//不知道为何这么写，反正觉得多余，注释掉，改成下面3行
				if(child.parent)
					(child.parent as GYSprite).delElement(child);
				s.elementVec.splice(index,0,child);
			}
			s.addChildAt(<egret.DisplayObject><any>child,index);
			s.invalidZIndex();
			return child;
		}
		/**移除元素*/
		public removeElement(child:IGYDisplay):IGYDisplay
		{var s = this;
			s.delElement(child);
			s.removeChild(<egret.DisplayObject><any>child);
			s.invalidZIndex();
			return child;
		}
		/**移除所有元素*/
		public removeAllElement():void
		{var s = this;			
			var len:number;
			len = s.elementVec.length;
			while(--len>-1)
				s.removeChild(<egret.DisplayObject><any>s.elementVec[len]);	
			s.elementVec.length = 0;			
		}
		/**移除指定层级的元素*/
		public removeElementAt(index:number):IGYDisplay
		{var s = this;
			var gySp:IGYDisplay=s.elementVec[index];
			s.elementVec.splice(index,1);
			s.removeChild(<egret.DisplayObject><any>gySp);
			s.invalidZIndex();
			return gySp;
		}
		
		/**设置元素层级*/
		public setElementIndex(child:IGYDisplay,index:number):void
		{var s = this;
			if(index >= s.elementVec.length)
				throw(new Error("索引" + index + "超出范围！"));
			var tempChild:IGYDisplay;
			tempChild = s.elementVec[index];
			if(tempChild == child)
				return;			
			s.setChildIndex(<egret.DisplayObject><any>child,index);
			s.elementVec.splice(s.elementVec.indexOf(child),1);
			s.elementVec.splice(index,0,child);			
			s.invalidZIndex();			
		}
		/**交换元素层级*/
		public swapElementIndex(child1:IGYDisplay,child2:IGYDisplay):void
		{var s = this;
			s.swapChildren(<egret.DisplayObject><any>child1,<egret.DisplayObject><any>child2);
			var tempIndex:number = s.elementVec.indexOf(child1);
			if(tempIndex == -1)
				throw(new Error("child1不在element列表内"));
			if(tempIndex >= s.elementVec.length)
				throw(new Error("索引" + tempIndex + "超出范围！"));
			var tempIndex2:number = s.elementVec.indexOf(child2);
			if(tempIndex2 == -1)
				throw(new Error("child2不在element列表内"));
			if(tempIndex2 >= s.elementVec.length)
				throw(new Error("索引" + tempIndex2 + "超出范围！"));
			if(tempIndex == tempIndex2)
				return;
			s.elementVec[tempIndex] = child2;
			s.elementVec[tempIndex2] = child1;
			s.invalidZIndex();
		}
		public set x(val:number)
		{
			let s = this;				
			if(!s.$setX(val))
				return;
			if(s.posCallUpdate)
                s.invalidDisplay();	
		}
		public set y(val:number)
		{
			let s = this;				
			if(!s.$setY(val))
				return;
			if(s.posCallUpdate)
                s.invalidDisplay();	
		}
		public get x():number
		{
			return this.$x;
		}
		public get y():number
		{
			return this.$y;
		}
		public set width(val:number)
		{
			this.set_width(val);
		}		
		public set height(val:number)
		{
			this.set_height(val);
		}		
		public get width():number
		{
			return this.get_width();
		}
		public get height():number
		{
			return this.get_height();
		}
		public set_width(val:number):boolean
		{
			let s = this;			
			if(s.$width == val)
				return false;
			s.$width = val;
			s.invalidDisplay();
			s.invalidLayout();
			return true;
		}
		public set_height(val:number):boolean
		{
			let s = this;	
			if(s.$height == val)
				return false;			
			s.$height = val;
			s.invalidDisplay();
			s.invalidLayout();
			return true;
		}
		public get_width():number
		{
			let s = this;
			if(s.$width != s.$width)							
				return s.getElementsBounds(s).width;							
			return s.$width;
		}
		public get_height():number
		{
			let s = this;
			if(s.$height != s.$height)							
				return s.getElementsBounds(s).height;							
			return s.$height;
		}
		/**设置百分比宽度,范围[0,1]*/
		public get percentWidth():number
		{var s = this;
			return s._layoutMode.percentWidth;
		}
		public set percentWidth(val:number)
		{var s = this;
			s._layoutMode.percentWidth=val;
			s.addLayout(<GYUIComponent>s.getLayoutContainer());
			s.sizeChange();
		}
		/**设置百分比高度,范围[0,1]*/
		public get percentHeight():number
		{var s = this;
			return s._layoutMode.percentHeight;
		}
		public set percentHeight(val:number)
		{var s = this;
			s._layoutMode.percentHeight=val;
			s.addLayout(<GYUIComponent>s.getLayoutContainer());
			s.sizeChange();
		}
		/**是否百分比的宽高*/
		public isPercentSize():boolean
		{var s = this;
			return s._layoutMode.isPercentSize();
		}
		public set layoutMode(val:LayoutMode)
		{var s = this;
			s._layoutMode = val;
			s.addLayout(<GYUIComponent>s.getLayoutContainer());
			s.sizeChange();
			s.layout();
		}
		/**布局对象*/
		public get layoutMode():LayoutMode
		{var s = this;
			return s._layoutMode;
		}

		public viewChange():void
        {let s = this;			
			s.layout();			
            if(s.viewChangeCallParent && (<any>s.parent).viewChange!=null)
                (<any>s.parent).viewChange();
		}
		
		/**重写s.updateView可以为其添加延时计算的内容(做法仿照s.invalidDisplay)，GYSprite内置了布局s.layout以及子级布局s.childLayout的延时计算		 
		 * 切记避免死循环的延时计算，例如延时执行A，在A的执行里面又触发了A的延时执行
		 * */
		public updateView():void
		{var s = this;
			if(s._invalidBatch)
			{
				s.validBatch();
				s._invalidBatch = false;				
			}
			if(s._invalidZIndex)
			{
				s.validZIndex();
				s._invalidZIndex = false;
			}
			if(s._invalidDisplay)
			{
				s.viewChange();
				s._invalidDisplay = false;
			}
			if(s._invalidLayout)
			{
				s.childLayout();
				s._invalidLayout = false;
			}			
		}
		/**css层级显示*/
		public invalidZIndex():void
		{let s = this;
			if(s._disabledZIndex)
				return;
			if(s._invalidZIndex)
				return;
			s._invalidZIndex = true;
			s.displayChg();
		}
		public validZIndex():void
		{
		}
		/**刷新显示*/
		public invalidDisplay():void
		{var s = this;
			if(s._invalidDisplay)
				return;
			s._invalidDisplay = true;
			s.displayChg();
		}
		/**刷新子级布局*/
		public invalidLayout():void
		{var s = this;
			if(s._invalidLayout)
				return;
			s._invalidLayout = true;
			s.displayChg();
		}
		/**禁止zindex层级排序*/
		public get disabledZIndex():boolean
		{
			return this._disabledZIndex;
		}
		public set disabledZIndex(val:boolean)
		{
			this._disabledZIndex = val;
		}		
		/**添加父级布局容器，以便父级变化时通知子级布局
		 * @param p父级容器
		 * */
		public addLayout(p:GYUIComponent):void
		{var s = this;
			if(s.$layoutParent == p)
				return;
			if(s.$layoutParent)
				s.$layoutParent.removeEventListener(GYViewEvent.VIEWCHANGE,s.layoutChange,s);
			if(s._layoutMode.isPercentSize() || s._layoutMode.layoutMode == LayoutMode.RELATIVE)
			{
				s.$layoutParent = p;
				if(s.$layoutParent)
					s.$layoutParent.addEventListener(GYViewEvent.VIEWCHANGE,s.layoutChange,s);
			}
			else
				s.$layoutParent = null;
		}
		/**获取布局容器(因为存在双层容器如GYGroup，用此方法取相对布局容器更准确)*/
		public getLayoutContainer():egret.DisplayObjectContainer
		{var s = this;
			if(s.offLayout)
				return <GYUIComponent>s.parent;								
			return <GYUIComponent>(s.parent && s.parent["__proto__"].constructor == InnerSprite?s.parent.parent:s.parent);
		}
		/**父级*/
		public get layoutParent():GYUIComponent
		{var s = this;
			return s.$layoutParent;
		}
		protected layoutChange(e:GYViewEvent):void
		{var s = this;
			s.sizeChange();
			s.layout();
		}
		public set left(val:number)
		{var s = this;
			s._layoutMode.left=val;
			s.addLayout(<GYUIComponent>s.getLayoutContainer());
			s.invalidDisplay();
		}
		public set top(val:number)
		{var s = this;
			s._layoutMode.top=val;
			s.addLayout(<GYUIComponent>s.getLayoutContainer());
			s.invalidDisplay();
		}
		public set right(val:number)
		{var s = this;
			s._layoutMode.right=val;
			s.addLayout(<GYUIComponent>s.getLayoutContainer());
			s.invalidDisplay();
		}
		public set bottom(val:number)
		{var s = this;
			s._layoutMode.bottom=val;
			s.addLayout(<GYUIComponent>s.getLayoutContainer());
			s.invalidDisplay();
		}
		public set horizonalCenter(val:number)
		{var s = this;
			s._layoutMode.horizonalCenter=val;
			s.addLayout(<GYUIComponent>s.getLayoutContainer());
			s.invalidDisplay();
		}
		public set verticalCenter(val:number)
		{var s = this;
			s._layoutMode.verticalCenter = val;
			s.addLayout(<GYUIComponent>s.getLayoutContainer());
			s.invalidDisplay();
		}
		/**相对左边布局*/
		public get left():number
		{var s = this;
			return s._layoutMode.$left;
		}
		/**相对顶部布局*/
		public get top():number
		{var s = this;
			return s._layoutMode.$top;
		}
		/**相对右边布局*/
		public get right():number
		{var s = this;
			return s._layoutMode.$right;
		}
		/**相对底边布局*/
		public get bottom():number
		{var s = this;
			return s._layoutMode.$bottom;
		}
		/**水平居中*/
		public get horizonalCenter():number
		{var s = this;
			return s._layoutMode.$horizonalCenter;
		}
		/**垂直居中*/
		public get verticalCenter():number
		{var s = this;
			return s._layoutMode.$verticalCenter;
		}
		public childLayout():void
		{var s = this;
			var len:number;
			len=s.elementVec.length;
			while(--len>-1)
			{
				var child:IGYDisplay;
				child=s.elementVec[len];
				child.sizeChange();
			}
		}
		/**刷新相对布局*/
		public layout():void
		{var s = this;
			if(CommonUtil.GYIs(s.$layoutParent,GYUIComponent))//此处得判断是否GYUIComponent来实施布局
			{
				if(s._layoutMode.top == s._layoutMode.top && s._layoutMode.bottom == s._layoutMode.bottom)				
					s.height=s.$layoutParent.borderHeight - s._layoutMode.top - s._layoutMode.bottom;				
				if(s._layoutMode.left == s._layoutMode.left && s._layoutMode.right == s._layoutMode.right)
					s.width=s.$layoutParent.borderWidth - s._layoutMode.left - s._layoutMode.right;

				if(s._layoutMode.top == s._layoutMode.top)
				{
					s.y=s._layoutMode.top;					
				}
				else if(s._layoutMode.bottom == s._layoutMode.bottom)
				{
					s.y=s.$layoutParent.height - s.height - s._layoutMode.bottom;
				}			
				else if(s._layoutMode.verticalCenter == s._layoutMode.verticalCenter)
				{
					s.y=(s.$layoutParent.height - s.height>>1)+s._layoutMode.verticalCenter;
				}
				if(s._layoutMode.left == s._layoutMode.left)
				{
					s.x=s._layoutMode.left;					
				}
				else if(s._layoutMode.right == s._layoutMode.right)
				{
					s.x=s.$layoutParent.width - s.width - s._layoutMode.right;
				}			
				else if(s._layoutMode.horizonalCenter == s._layoutMode.horizonalCenter)
				{
					s.x=(s.$layoutParent.width - s.width>>1)+s._layoutMode.horizonalCenter;
				}				
			}
		}
		/**刷新相对大小*/
		public sizeChange():void
		{var s = this;
			if(s.$layoutParent == null)
				return;			
			if(s._layoutMode.percentWidth == s._layoutMode.percentWidth)
			{
				s.width=s.$layoutParent.borderWidth * s._layoutMode.percentWidth;
			}			
			if(s._layoutMode.percentHeight == s._layoutMode.percentHeight)
			{
				s.height=s.$layoutParent.borderHeight * s._layoutMode.percentHeight;
			}
		}
		public get numElement():number
		{var s = this;
			return s.elementVec.length;
		}		
		/**获取设定的宽度*/
		public get settingWidth():number
		{var s = this;
			return s.$width;
		}
		/**获取设定的高度*/
		public get settingHeight():number
		{var s = this;
			return s.$height;
		}		
		/**提示文本,可以通过s.toolTip设置自定义的GYToolTip(继承此类重写实现)*/
		public set toolTipString(val:string)
		{var s = this;
			if(val == null)
			{
				s.toolTip = null;
				s._toolTipString = null;
				return;
			}
			s._toolTipString = val;
			if(s._toolTip == null)
				s.toolTip = GYSprite.skinTheme.GetToolTip();
			if(<any>s._toolTip.user == s)
				s._toolTip.setText(val);
		}
		public get toolTipString():string
		{var s = this;
			return s._toolTipString;
		}
		public set toolTip(val:GYToolTip)
		{var s = this;
			if(s._toolTip)
				s.removeEventListener(MouseEvent.ROLL_OVER, s.rollOverTip,s);
			s._toolTip = val;
			if(s._toolTip)
				s.addEventListener(MouseEvent.ROLL_OVER, s.rollOverTip,s);
		}
		/**s.toolTip，继承GYToolTip实现自定义@see GYToolTip*/
		public get toolTip():GYToolTip
		{var s = this;
			return s._toolTip;
		}
		protected rollOverTip(e:egret.TouchEvent=null):void
		{var s = this;
			if(s._toolTip.parent == null)
				s.showTip(false);
		}
		public showTip(keep:boolean = false, followTarget:GYSprite = null):void
		{var s = this;
			s._toolTipOnKeep = keep || s._toolTipKeep;
			if(s._toolTipOnKeep)
			{
				GYSprite.addStageDown(s,s.rollOutTip, s);
				s.addEventListener(egret.TouchEvent.TOUCH_END,s.mouseOutTip,s);
				s.removeEventListener(MouseEvent.ROLL_OUT, s.rollOutTip,s);
			}
			else
			{
				s.addEventListener(MouseEvent.ROLL_OUT, s.rollOutTip,s);
			}
			s._toolTip.user = this;
			s._toolTip.tipfollowTarget = s._followTarget?s._followTarget:followTarget;
			if(s._toolTip.parent == null)
			{
				s._toolTip.setText(s._toolTipString);
				s._toolTip.offsetX = s.toolTipOffsetX;
				s._toolTip.offsetY = s.toolTipOffsetY;
				s._toolTip.show(GYSprite.$stage, s.isTipFollow);
			}
		}
		protected rollOutTip(e:egret.TouchEvent=null):void
		{var s = this;
			s.removeEventListener(MouseEvent.ROLL_OUT, s.rollOutTip,s);
			if(s._toolTip && s._toolTip.parent)
			{
				s._toolTip.hide();
			}
		}
		protected mouseOutTip(e:egret.TouchEvent=null):void
		{var s = this;
			s.removeEventListener(egret.TouchEvent.TOUCH_END,s.mouseOutTip,s);
			s._toolTipOnKeep = false;
			if(s._toolTip && s._toolTip.parent)
			{
				s._toolTip.hide();
			}
		}
		/**tip偏移量X*/
		public get toolTipOffsetX():number
		{var s = this;
			return s._toolTipOffsetX;
		}

		public set toolTipOffsetX(value:number)
		{var s = this;
			s._toolTipOffsetX = value;
		}
		/**tip偏移量Y*/
		public get toolTipOffsetY():number
		{var s = this;
			return s._toolTipOffsetY;
		}

		public set toolTipOffsetY(value:number)
		{var s = this;
			s._toolTipOffsetY = value;
		}
		/**是否保留tip直到鼠标抬起*/
		public get toolTipKeep():boolean
		{var s = this;
			return s._toolTipKeep;
		}

		public set toolTipKeep(value:boolean)
		{var s = this;
			s._toolTipKeep = value;
			if(s._toolTip.parent)
			{
				GYSprite.addStageDown(s,s.rollOutTip, s);
				s.addEventListener(egret.TouchEvent.TOUCH_END,s.rollOutTip,s);
				s.removeEventListener(MouseEvent.ROLL_OUT, s.rollOutTip,s);
			}
		}
		/**tip跟随对象*/
		public get followTarget():GYSprite
		{var s = this;
			return s._followTarget;
		}

		public set followTarget(value:GYSprite)
		{var s = this;
			s._followTarget = value;
		}
		/**是否刷新中（内部使用请勿修改）*/
		public get updating():boolean
		{var s = this;
			return s._updating;
		}

		public set updating(value:boolean)
		{var s = this;
			s._updating = value;
		}

		public getElementList():Array<IGYDisplay>
		{
			return this.elementVec;
		}

		/**是否在父级视图范围内(0,0,width,height),可用于做裁切视图时的离屏渲染优化*/
		public inParentView(l:number=0,r:number=0,t:number=0,b:number=0):boolean
		{let s = this;
			let pr:egret.DisplayObjectContainer;
			let sX:number,sY:number,sW:number,sH:number;
			pr = s.parent;
			if(pr)
			{
				if(CommonUtil.GYIs(pr.parent,GYGroup))
				{
					pr = pr.parent;
					sX = (<GYGroup>pr).clipX;
					sY = (<GYGroup>pr).clipY;					
				}
				else
				{
					if(pr.scrollRect)
					{
						sX = pr.scrollRect.x;
						sY = pr.scrollRect.y;
					}
					else
					{
						sX = 0;
						sY = 0;
					}
				}	
				sW = pr.width;
				sH = pr.height;
				if(s.y > sY + sH + b || s.x > sX + sW + r || s.x + s.width * s.$scaleX < sX + l || s.y + s.height * s.$scaleY < sY + t)
					return false;	
				return true;
			}
			return false;
		}
		/**销毁
		 * @param disposeChild 是否连同显示列表上的子级也销毁，默认true
		 * @param removeChild 是否从父级显示列表中移除，默认true
		 * @param forceDispose 是否强制销毁，为true表示无视disposeLock标志，进行销毁，默认false
		*/
		public dispose(disposeChild:boolean=true, removeChild:boolean = true, forceDispose:boolean=false):void
		{let s= this;
			let len:number;
			if(s.$disposed)return;
			if(s.disposeLock && !forceDispose)return;
			s.graphics.clear();
			s.setWheelFunc(null,null);
			s.$disposed = true;
			if(disposeChild)
			{
				len = s.elementVec.length;
				while(--len>-1)
				{
					s.elementVec[len].dispose(true, false, forceDispose);//子级必须依赖父级一块销毁，disposeChild=true，但是没必要移除，所以removeChild=false
				}
			}			
			if(removeChild && s.parent)
			{
				let p:any = s.getLayoutContainer();
				if(GYLite.CommonUtil.GYIs(p, GYSprite))
					p.removeElement(this);
				else
					p.removeChild(this);
			}			
		}
		/**是否已经被销毁*/
		public get disposed():boolean
		{
			return this.$disposed;
		}		
		public invalidBatch():void
		{
			let s= this;
			if(s._invalidBatch)
				return;
			s._invalidBatch = true;
			s.displayChg();
		}
		public validBatch():void
		{			
			return;
		}
		public enableBatch(val:boolean)
		{
			this._batch = val;			
		}
		/**是否动态合批，请在文本渲染前设定，默认根据父级容器batch，如果父级也没设定，则默认false*/
		public isBatch():boolean
		{var s = this;
			if(s._batch !== undefined)
				return s._batch;			
			let pr:GYSprite;
			pr = <GYSprite>s.$parent;			
			return pr && pr.isBatch && pr.isBatch();
		}	
	}

export class MouseWheel {
	private static _pool:MouseWheel[];
	public static getInstance(d:IGYDisplay,callBack:Function,thisObject:any):MouseWheel
	{
		var m:MouseWheel;
		if(!MouseWheel._pool)
		{
			MouseWheel._pool=new Array<MouseWheel>();
		}
		m = MouseWheel._pool.length==0?new MouseWheel():MouseWheel._pool.pop();
		m.callBack = callBack;
		m.display = d;
		m.thisObject = thisObject;			
		return m;
	}
	public callBack:Function;
	public display:IGYDisplay;	
	public thisObject:any;
}

export class MouseRelease {
	private static _pool:MouseRelease[];
	public static getInstance(d:IGYDisplay,callBack:Function,thisObject:any,touchPointID:number=NaN):MouseRelease
	{
		var m:MouseRelease;
		if(!MouseRelease._pool)
		{
			MouseRelease._pool=new Array<MouseRelease>();
		}
		m = MouseRelease._pool.length==0?new MouseRelease():MouseRelease._pool.pop();
		m.callBack = callBack;
		m.display = d;
		m.thisObject = thisObject;
		m.touchPointID = touchPointID == null?NaN:touchPointID;
		if(callBack!=null)
		{
			d.addEventListener(GYTouchEvent.RELEASE_OUTSIDE, callBack, thisObject!=null?thisObject:d);
		}			
		return m;
	}
	public callBack:Function;
	public display:IGYDisplay;
	public untilUp:boolean;
	public thisObject:any;
	public touchPointID:number;
	public constructor()
	{var s = this;
	}
	public clear():void
	{var s = this;
		if(s.display)
		{
			MouseRelease._pool.push(this);
			if(s.callBack!=null)
				s.display.removeEventListener(GYTouchEvent.RELEASE_OUTSIDE, s.callBack, s.thisObject?s.thisObject:s.display);
			s.callBack = null;			
			s.untilUp = false;			
			s.display = null;
			s.touchPointID = NaN;
			s.thisObject = null;
		}
	}
}
}


